package com.onpositive.mediawiki.propertyparser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;

import com.onpositive.semantic.model.api.labels.TextProviderAdapter;
import com.onpositive.semantic.model.api.realm.AbstractFilter;
import com.onpositive.units.ParsedFileList;
import com.onpositive.units.ParsedProperty;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;
import com.onpositive.wikistorage.PictureManager;


public class ParsedDocument {
	
	public static final String PICTURE_LIST_PROPERTY_NAME = "files" ;
	private static final String CATEGORY_SEPARATOR = "\\;" ;
	
	private ParsedCategory category ;
	private boolean isActual = true ;
	
	private HashSet<String> parentCategoryNames = new HashSet<String>() ;
	private HashSet<ParsedDocument> parentCategories = new HashSet<ParsedDocument>() ;
	
	public ParsedDocument(){
		
	}
	public ParsedDocument( String name){
		this.name = name ;	
	}
	
	
	public void setCategory(ParsedCategory category) {
		this.category = category;
	}
	
	public HashSet<ParsedDocument> getParentCategories() {
		
		if( category == null )
			return null ;
		
		if( parentCategories == null || parentCategories.size() == 0 )
			updateParentCategories() ;
		
		return parentCategories;
	}

	private void updateParentCategories() {
		if( category == null )
			return ;
		
		if( parentCategories == null )
			parentCategories = new HashSet<ParsedDocument>() ;
		
		parentCategories.clear() ;
		HashSet<String> invalidDocumentNames = new HashSet<String>() ;
		for( String n : parentCategoryNames ){
			ParsedDocument pDoc = category.getParsedDocument(n);
			if( pDoc != null )
				parentCategories.add( pDoc ) ;
			else
				invalidDocumentNames.add(n) ;
		}
		
		for( String n : invalidDocumentNames )
			parentCategoryNames.remove(n) ;
		
	}

	public void setParentCategories( Collection<ParsedDocument> parentCategories) {
		this.parentCategories = new HashSet<ParsedDocument>( parentCategories );
		
		updateParentCategoryNames() ;
	}

	private void updateParentCategoryNames() {
		if( parentCategories == null || parentCategories.size() == 0 )
			return ;
		
		parentCategoryNames.clear() ;
		for( ParsedDocument doc : parentCategories )
			parentCategoryNames.add( doc.getName() ) ;		
	}

	private String defaultPicture = "" ;
	
	public String getDefaultPicture() {
		return defaultPicture;
	}

	public void setDefaultPicture(String defaultPicture) {
		if ( checkPictureExistance(defaultPicture) )
			this.defaultPicture = defaultPicture;
	}

	private String name = null;

	protected HashMap<String, ParsedProperty> props=new HashMap<String, ParsedProperty>();
	
	public HashMap<String, ParsedProperty> getProps() {
		return props;
	}
	
	public void setName( String name )
	{
		this.name = name ;
	}
	public String getName()
	{
		return this.name ;
	}
	
	public HashSet<String> getParentCategoryNames() {
		
		if( parentCategoryNames.size() == 0 )
			return null ;
		
		return parentCategoryNames;
	}

	public void setParentCategoryNames( Collection<String> parenCategories) {
		
		this.parentCategoryNames = new HashSet<String>( parenCategories );		
		updateParentCategories() ;
	}
	
	public void addParentCategory( String name )
	{
		parentCategoryNames.add( name ) ;
		
		updateParentCategories() ;
	}
	
	public String getParentCategoriesString(){
		
		if ( this.parentCategoryNames.size() == 0 )
			return "" ;
		
		String result = "" ;
		for( String cat : this.parentCategoryNames )
			result += cat + " " + CATEGORY_SEPARATOR ;
		
		return result.substring( 0, result.length() - CATEGORY_SEPARATOR.length() ).trim() ;
	}
	
	public void setParentCategoriesString( String _s )
	{
		String s = _s.trim() ;
		if( s == null || s.length() == 0 )
			return ;
		
		String[] catArr = s.split( CATEGORY_SEPARATOR ) ;
		this.parentCategoryNames.clear() ;
		for( String cat : catArr )
			if( cat.length() > 0 )
				this.parentCategoryNames.add( cat.trim() ) ;
		
		updateParentCategories() ;
	}
	
	public void addProperty( ParsedProperty property )
	{		
		props.put( property.getName(), property ) ;
	}
	
	public ParsedProperty getPropertyForContribution( String propName  )
	{
		ParsedProperty prop = props.get( propName) ;
		if( prop == null ){
			prop = new ParsedProperty( propName ) ;
			props.put( propName, prop ) ;
		}
		return prop ;
	}
	
	public ParsedProperty getProperty( String propName )
	{
		return props.get(propName) ;	
	}
	
	boolean checkPictureExistance( String path ){
		
		return PictureManager.getInstance( category.getRootPath() ).checkPicturePresence( path, this.name ) ;	
	}
	
	public String getRootParh()
	{
		return category != null ? category.getRootPath() : null ;
	}
	
	public void setDefaultPicture()
	{
		ParsedProperty prop = this.getProperty(PICTURE_LIST_PROPERTY_NAME) ;
		if( prop == null )
			return ;
		
		ArrayList<String> wikiPaths = new ArrayList<String>() ;
		for( ParsedValue val : prop.values )
		{
			if( !( val instanceof ParsedFileList ) )
				continue ;
			
			ArrayList<String> lst = (ArrayList<String>) val.value() ;
			for( String s : lst )
				wikiPaths.add(s) ;
		}
		if( wikiPaths.size() == 0 )
			return ;
		
		for( String str : wikiPaths ){
			if( str.startsWith("http:") )
				continue ;
			
			if( !PictureManager.getInstance( category.getRootPath() ).checkPicturePresence( str, this.name ) )
				continue ;
			
			this.defaultPicture = str ;
			break ;
		}

	}
	
	public static class DefaultPictureExistanceFilter extends AbstractFilter{

		@Override
		public boolean accept(Object element) {
			try{
				String defaultpicture = ((ParsedDocument)element).getDefaultPicture() ;
				return !(defaultpicture!= null && defaultpicture.length()>0 );
			}catch( ClassCastException e)
			{
				return true;
			}
		}	
	}
	
	public static class NameLabelProvider extends TextProviderAdapter{

		@Override
		public String getText(Object object) {
			if (object!=null){
			return ((ParsedDocument)object).getName();
			}
			return "null";
		}

		@Override
		public String getDescription(Object object) {
			return getText( object );
		}
		
	}
	public void extractLinks( ParsedCategory _category )
	{
		ArrayList<String> ownLinks = getOwnLinks() ;
		HashSet<String> categoryLinks = _category.getLinks() ;
		HashSet<String> categoryLinksCaptions = _category.getLinkCaptions() ;
		for( String s : ownLinks ) {
			if( s == null || s.length() == 0)
				continue ;
			String str = s.trim().replaceAll(" ", "_");
			if( str.length() != 0 ){
				if( str.startsWith("|") )
					categoryLinksCaptions.add( str.substring(1).trim() ) ;
				else
					categoryLinks.add( str ) ;
			}
		}				
	}
	private ArrayList<String> getOwnLinks() {
		
		ArrayList<String> links = new ArrayList<String>() ;
		for( ParsedProperty prop : this.props.values() )
		{
			for( ParsedValue val : prop.getValues() )
				getLinksFromValue( links, val ) ;								
		}		
		return links ;
	}
	private void getLinksFromValue( ArrayList<String> ownLinks, ParsedValue val )
	{
		if( !(val instanceof ParsedValueSequence) )
			return ;
		
		String valString = val.getValueAsString() ;
		
		for( int i = valString.indexOf("[[") ; i >= 0 ; i = valString.indexOf( "[[", i+2 )  )
		{
			i += 2 ;
			int j = valString.indexOf("]]",i) ;
			int k = valString.indexOf("|",i) ;
			k = k < 0 ? Integer.MAX_VALUE : k ; 
			k = Math.min( j , k );
			
			String s = null ;
			try{
			s = valString.substring( i,k );
			}catch(Exception e)
			{
				e.printStackTrace() ;
				break;				
			}				
			ownLinks.add( s );
			if( k != j )
				ownLinks.add( valString.substring(k,j) );
				
			i = j ;			
		}
	}
	public boolean isActual() {
		return isActual;
	}
	public void setActual(boolean isActual) {
		this.isActual = isActual;
	}
	public ParsedCategory getCategory() {
		return category;
	}
}
